#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>

#include "func.h"
#include "wasApp.h"



/**
 * @brief  
 * @date   2023-07-12 08:57:50
 * @author xiaole
 * @param  num
 * @param  src
 * @param  bit
 * @return true
 * @return false
 * @note
 */
bool bin_set_bit(unsigned int *num, long src, const long long bit)
{
	if(src < 0)
	{
		LOG_RED("err: num is invalid '%ld' < '0'\n", src);
		return false;
	}

	if(bit < src)
	{
		LOG_RED("err: num is too large  '%ld' > '%lld'\n", src, bit);
		return false;
	}


    switch (bit)
    {
        case 0x0000000F:			
			*num = (*num & ~bit) | src ;
			break;
        case 0x000000F0:
			*num = (*num & ~bit) | src  << 4;
			break;
        case 0x00000F00:
			*num = (*num & ~bit) | src  << 8;
			break;
        case 0x0000F000:
			*num = (*num & ~bit) | src  << 12;
			break;	
        case 0x000F0000:
			*num = (*num & ~bit) | src  << 16;
			break;	
        case 0x00F00000:
			*num = (*num & ~bit) | src  << 20;
			break;	
        case 0x0F000000:
			*num = (*num & ~bit) | src  << 24;
			break;	
        case 0xF0000000:
			*num = (*num & ~bit) | src  << 28;
			break;


        case 0x000000FF:
			*num = (*num & ~bit) | src ;
			break;
        case 0x0000FF00:
			*num = (*num & ~bit) | src  << 8;
			break;
        case 0x00FF0000:
			*num = (*num & ~bit) | src  << 16;
			break;
        case 0xFF000000:
			*num = (*num & ~bit) | src  << 24;
			break;

		case 0x0000FFFF:
			*num = (*num & ~bit) | src ;
			break;		
		case 0x00FFFF00:
			*num = (*num & ~bit) | src << 8;
			break;
		case 0xFFFF0000:
			*num = (*num & ~bit) | src << 16;
			break;
        
        default:
			LOG_RED("bit %#08llX is not avliable...\n", bit);
			break;
    }

	return true;
}



int bin_get_bit(int num, const int bit)
{
    switch (bit)
    {
	case 0x0000000F:
        num = (num & bit);
        break;
	case 0x000000F0:
        num = (num & bit) >> 4;
        break;		
	case 0x00000F00:
        num = (num & bit) >> 8;
        break;
	case 0x0000F000:
        num = (num & bit) >> 12;
        break;
	case 0x000F0000:
        num = (num & bit) >> 16;
        break;	
	case 0x00F00000:
        num = (num & bit) >> 20;
        break;
	case 0x0F000000:
        num = (num & bit) >> 24;
        break;
	case 0xF0000000:
        num = (num & bit) >> 28;
        break;

    case 0x000000FF:    /* 低8 */
        num = (num & bit) >> 0;
        break;
    case 0x0000FF00:    /* 高8 */
        num = (num & bit) >> 8;
        break;
    case 0x00FF0000:
        num = (num & bit) >> 16;
        break;
    case 0xFF000000:
        num = (num & bit) >> 24;
        break;

	case 0x0000FFFF:
		num = (num & bit) >> 0;
		break;		
	case 0x00FFFF00:
		num = (num & bit) >> 8;
		break;
	case 0xFFFF0000:
		num = (num & bit) >> 16;
		break;
    
    default:
        LOG_RED("bit %#08X is not avliable...\n", bit);
        break;
    }

    return num;
}

const char *bin_print(int num)
{
	static char buf[] = "00000000 00000000 00000000 00000000\0";
	memset(buf, 0, sizeof(buf));

	int i, j, m = 0;
	unsigned char *p = (unsigned char *)&num + 3; 	// p先指向num后面第3个字节的地址，即num的最高位字节地址
	for (i = 0; i < 4; i++) 						// 依次处理4个字节(32位）
	{
		j = *(p - i);				 				// 取每个字节的首地址，从高位字节到低位字节，即p p-1 p-2 p-3地址处
		for (int k = 7; k >= 0; k--) 				// 处理每个字节的8个位，注意字节内部的二进制数是按照人的习惯存储！
		{			
			if (j & (1 << k)) 						// 1左移k位，与单前的字节内容j进行或运算，如k=7时，00000000 & 10000000=0 ->该字节的最高位为0
			{
				buf[m++] = '1';
			}
			else
			{
				buf[m++] = '0';
			}
		}
		buf[m++] = ' ';	// 每8位加个空格，方便查看
		
	}
	return buf;


	#if (0)
	{
		// 使用unsigned char来验证int的每一个字节
		unsigned char *p1 = (unsigned char *)&num;	   // 获取a的首地址
		unsigned char *p2 = (unsigned char *)&num + 1; // 获取a的首地址的后一个字节地址
		unsigned char *p3 = (unsigned char *)&num + 2; // 获取a的首地址的后两个字节地址
		unsigned char *p4 = (unsigned char *)&num + 3; // 获取a的首地址的后三个字节地址

		printf(" p1:%p, %d\r\n", p1, *p1); // 打印p1的地址与存储的字节内容
		printf(" p2:%p, %d\r\n", p2, *p2); // 打印p2的地址与存储的字节内容
		printf(" p3:%p, %d\r\n", p3, *p3); // 打印p3的地址与存储的字节内容
		printf(" p4:%p, %d\r\n", p4, *p4); // 打印p4的地址与存储的字节内容
	}
	#endif
}


bool file_is_exists(const char *file_path)
{
	if(access(file_path, F_OK) == 0)
	{
		return true;
	}

	return false;
}

int file_get_num(const char *path)
{
	DIR *dir = opendir(path);
	if(dir == NULL)
	{
		LOG_RED("err: open dir %s fail...\n", path);
		return 0;
	}

	struct dirent *ptr;
	int total_file_num = 0;

	while ((ptr = readdir(dir)) != NULL)
	{
		char *d_name = ptr->d_name;


		/* 过滤 . 和 .. */
		if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0)	continue;


		/* 是文件夹 */
		if (ptr->d_type == DT_DIR)
        {
            char new_path[256];
            sprintf(new_path, "%s/%s", path, d_name);	/* 将path和新的目录拼接起来 */            
            total_file_num += file_get_num(new_path);	/* 继续读取这个目录 */
        }

		/* 是普通文件 */
		if (ptr->d_type == DT_REG)
        {
            total_file_num++;
        }
            
	}

	closedir(dir);
	return total_file_num;
}


/*************************************************************************
 * @brief  月份字符串转成数字
 * @date   2023-03-18 15:13
 * @author xiaole
 * @return 对应的数字，  May -> 5， 无效时，返回0
 * @param  str 必须输入指定的才行， 
 * @note   有效字符， 用strncmp() 对比前3个字符
 *      "Jan", "Feb", "Mar", "Apr",
        "May", "Jun", "Jul", "Aug",
        "Sep", "Oct", "Nov", "Dec",
 **************************************************************************/
int month_str_to_num(const char* str)
{
    const char *month_group[] = {
        "Jan", "Feb", "Mar", "Apr",
        "May", "Jun", "Jul", "Aug",
        "Sep", "Oct", "Nov", "Dec",
    };

    for(int i = 0; i < 12; i++)
    {
        if(strncmp(str, month_group[i], 3) == 0)
        {
            return i+1;
        }
    }

    LOG_RED("'%s', maybe not a month word\n", str);
    return 0;
}




int rand_number_get(int min, int max)
{
    srand((unsigned)time(NULL) + rand());

	return (rand() % (max - min +1) + min);
}



unsigned long long xl_timestamp_get(void)
{
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return tv.tv_sec;
}


/**
 * @brief  获取当前时间戳(毫秒)
 * @date   2023-08-03 14:43:11
 * @author xiaole
 * @return unsigned long long
 * @note
 */
unsigned long long xl_timestamp_ms_get(void)
{
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}



